package com.itfitness.nervecat.gamewidget;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;

import com.itfitness.nervecat.R;
import com.itfitness.nervecat.beans.Dot;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @ProjectName: NerveCat
 * @Package: com.itfitness.nervecat.gamewidget
 * @ClassName: GameView
 * @Description: java类作用描述 ：
 * @Author: 作者名：lml
 * @CreateDate: 2019/4/8 11:15
 * @UpdateUser: 更新者：
 * @UpdateDate: 2019/4/8 11:15
 * @UpdateRemark: 更新说明：
 * @Version: 1.0
 */

public class GameView extends SurfaceView implements SurfaceHolder.Callback,View.OnTouchListener,Runnable{
    private GameCallback gameCallback;
    private Thread mThread;
    private static final int ROW = 10;
    private static final int COL = 10;
    private static final int BLOCKS = 15;//默认路障数量
    private int mStepNum = 0;//围住神萌萌用的步数
    private Paint mPaint;
    private Dot mMatrix[][];
    private Dot mCat;
    private Random mRandom;//随机数
    private int mDotWidth;
    private boolean mThreadFlag = true;//线程开关
    private int [] mAnimImages = {R.drawable.cat1,R.drawable.cat2,R.drawable.cat3,R.drawable.cat4,R.drawable.cat5,
            R.drawable.cat6,R.drawable.cat7,R.drawable.cat8,R.drawable.cat9,R.drawable.cat10,R.drawable.cat11,R.drawable.cat12,
            R.drawable.cat13,R.drawable.cat14,R.drawable.cat15,R.drawable.cat16};
    private int mAnimImagesIndex = 0;
    private Bitmap mAnimBitmap;
    private int mTopoffset;

    public GameView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化
        mThread = new Thread(this);
        setZOrderOnTop(true);
        getHolder().setFormat(PixelFormat.TRANSLUCENT);
        getHolder().addCallback(this);
        setOnTouchListener(this);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mRandom = new Random();
        mMatrix = new Dot[ROW][COL];
        initDots();
        initGame();
    }

    public GameView(Context context) {
        this(context,null);
    }

    public GameCallback getGameCallback() {
        return gameCallback;
    }

    public void setGameCallback(GameCallback gameCallback) {
        this.gameCallback = gameCallback;
    }

    /**
     * 获取Dot对象（行与列在x,y里是相反的）
     * @param x
     * @param y
     * @return
     */
    private Dot getDot(int x,int y){
        return mMatrix[y][x];
    }

    /**
     * 游戏初始化
     */
    public void initGame() {
        for(int i = 0;i<ROW;i++){
            for(int j = 0;j<COL;j++){
                mMatrix[i][j].setStatus(Dot.STATUS_OFF);
            }
        }
        mCat = new Dot(4,5);
        getDot(4,5).setStatus(Dot.STATUS_IN);
        for(int i = 0;i < BLOCKS;){
            int x = mRandom.nextInt(COL);
            int y = mRandom.nextInt(ROW);
            if(getDot(x,y).getStatus() == Dot.STATUS_OFF){
                getDot(x,y).setStatus(Dot.STATUS_ON);
                i++;
                Log.e("Block",i+"");
            }
        }
    }

    private void initDots() {
        for(int i = 0;i<ROW;i++){
            for(int j = 0;j<COL;j++){
                mMatrix[i][j] = new Dot(j,i);
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mThreadFlag=true;
        mThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mDotWidth = (int) (width / (ROW+0.5));
        mTopoffset = height-mDotWidth*ROW;
    }

    /**
     * 绘制点
     */
    private void drawDots(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        for(int i = 0;i<ROW;i++){
            for(int j = 0;j<COL;j++){
                Dot dot = mMatrix[i][j];
                int offset = 0;
                if(i%2!=0){
                    offset = mDotWidth /2;
                }
                switch (dot.getStatus()){
                    case Dot.STATUS_IN:
                        mPaint.setColor(Color.WHITE);
                        break;
                    case Dot.STATUS_OFF:
                        mPaint.setColor(Color.GRAY);
                        break;
                    case Dot.STATUS_ON:
                        mPaint.setColor(Color.RED);
                        break;
                }
                canvas.drawOval(new RectF(dot.getX()* mDotWidth +offset,dot.getY()* mDotWidth+mTopoffset,(dot.getX()+1)* mDotWidth +offset,(dot.getY()+1)* mDotWidth+mTopoffset),mPaint);
            }
        }
    }

    /**
     * 是否在边缘
     * @param dot
     * @return
     */
    private boolean isAtEdge(Dot dot){
        if(dot.getX()*dot.getY()==0||dot.getX()+1==COL||dot.getY()+1==ROW){
            return true;
        }
        return false;
    }

    /**
     * 获取相邻点的对象
     * @param dot
     * @param index
     * @return
     */
    private Dot getNeighbor(Dot dot,int index){
        switch (index){
            case 1:
                return getDot(dot.getX()-1,dot.getY());
            case 2:
                if(dot.getY()%2==0){
                    return getDot(dot.getX()-1,dot.getY()-1);
                }else {
                    return getDot(dot.getX(),dot.getY()-1);
                }
            case 3:
                if(dot.getY()%2==0){
                    return getDot(dot.getX(),dot.getY()-1);
                }else {
                    return getDot(dot.getX()+1,dot.getY()-1);
                }
            case 4:
                return getDot(dot.getX()+1,dot.getY());
            case 5:
                if(dot.getY()%2==0){
                    return getDot(dot.getX(),dot.getY()+1);
                }else {
                    return getDot(dot.getX()+1,dot.getY()+1);
                }
            case 6:
                if(dot.getY()%2==0){
                    return getDot(dot.getX()-1,dot.getY()+1);
                }else {
                    return getDot(dot.getX(),dot.getY()+1);
                }
        }
        return null;
    }

    /**
     * 获取各个相邻方向的与路障或场景边缘的距离（路障为负数，边缘为正数）
     * @param dot
     * @param index
     * @return
     */
    private int getDistance(Dot dot,int index){
        int distance = 0;
        Dot ori,next;
        ori = dot;
        while (true){
           next = getNeighbor(ori,index);
            if (next.getStatus() == Dot.STATUS_ON){//碰到路障
                return distance*-1;
            }
            if (isAtEdge(next)){//碰到边缘
                distance++;
                return distance;
            }
            distance++;
            ori = next;
        }
    }

    /**
     * 移动
     * @param movedot
     */
    private void moveTo(Dot movedot){
        movedot.setStatus(Dot.STATUS_IN);
        getDot(mCat.getX(),mCat.getY()).setStatus(Dot.STATUS_OFF);
        mCat.setXY(movedot.getX(),movedot.getY());
    }

    /**
     * 判断是否还有移动的空间
     */
    private void isHaveSpace(){
        if(isAtEdge(mCat)){
            lose();
            return;
        }
        HashMap<Integer,Dot> noBlocks = new HashMap<>();//无路障
        HashMap<Integer,Dot> haveBlocks = new HashMap<>();//有路障
        for(int i=1;i<7;i++){
            Dot neighbor = getNeighbor(mCat, i);
            if(neighbor.getStatus() == Dot.STATUS_OFF){
                int distance = getDistance(mCat, i);
                if(distance>0){
                    //无路障
                    noBlocks.put(distance,neighbor);
                }else if (distance<0){
                    //有路障
                    haveBlocks.put(distance,neighbor);
                }
            }
        }
        if(noBlocks.size()==0&&haveBlocks.size()==0){
            win();
        }else if(noBlocks.size()>0){
            Integer temp = 999;
            for (Map.Entry<Integer, Dot> entry : noBlocks.entrySet()) {
                if(temp > entry.getKey()){
                    temp = entry.getKey();
                }
            }
            moveTo(noBlocks.get(temp));//进行移动
        }else {
            Integer temp = 0;
            for (Map.Entry<Integer, Dot> entry : haveBlocks.entrySet()) {
                if(temp > entry.getKey()){
                    temp = entry.getKey();
                }
            }
            moveTo(haveBlocks.get(temp));//进行移动
        }
    }

    /**
     * 失败
     */
    private void lose(){
        if(gameCallback!=null){
            gameCallback.onLose();
        }
    }
    /**
     * 成功
     */
    private void win(){
        if(gameCallback!=null){
            gameCallback.onWin(mStepNum);
        }
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mThreadFlag = false;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_UP){
            int x,y;
            y = (int) ((event.getY()-mTopoffset)/mDotWidth);
            if(y%2==0){
                x = (int) ((event.getX()+mDotWidth/2)/mDotWidth);
            }else {
                x = (int) (event.getX()/mDotWidth);
            }
            if(!(x+1>COL||y+1>ROW)) {
                Dot dotSelect = getDot(x, y);
                if(dotSelect.getStatus()==Dot.STATUS_OFF){
                    mStepNum++;
                    dotSelect.setStatus(Dot.STATUS_ON);
                    isHaveSpace();
                    if(isAtEdge(mCat)){
                        lose();
                    }
                }
            }
        }
        return true;
    }

    @Override
    public void run() {
        while (mThreadFlag){
            try {
                Canvas canvas = getHolder().lockCanvas();
                if(canvas==null){
                    continue;
                }
                drawDots(canvas);
                drawImages(canvas);
                getHolder().unlockCanvasAndPost(canvas);
                Thread.sleep(100);
            }catch (Exception e){}
        }
    }

    /**
     * 画动画
     * @param canvas
     */
    private void drawImages(Canvas canvas) {
        if(mAnimImagesIndex >= mAnimImages.length-1){
            mAnimImagesIndex = 0;
        }
        int mAnimImage = mAnimImages[mAnimImagesIndex];
        Bitmap bitmapTemp = BitmapFactory.decodeResource(getResources(), mAnimImage);
        mAnimBitmap = Bitmap.createScaledBitmap(bitmapTemp, mDotWidth, (int) (mDotWidth*1.45), false);
        bitmapTemp.recycle();
        if(mCat.getY()%2==0){
            canvas.drawBitmap(mAnimBitmap,mCat.getX()*mDotWidth,mCat.getY()*mDotWidth-((int) (mDotWidth*1.45)-mDotWidth+mDotWidth/3)+mTopoffset,null);
        }else {
            canvas.drawBitmap(mAnimBitmap,mCat.getX()*mDotWidth+mDotWidth/2,mCat.getY()*mDotWidth-((int) (mDotWidth*1.45)-mDotWidth+mDotWidth/3)+mTopoffset,null);
        }
        mAnimImagesIndex++;
    }
}
